
//
// Copyright 2009 Arne Halvorsen (arne.halvorsen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Project page: http://code.google.com/p/webfg/

//
// 091201 - aha42 - Created.
// 091213a- aha42 - Now picks up title to override picture's proper title in
//                  gallery from tag webfg.title.
// 091213b- aha42 - Now picks up size from webfg.size tag to override m for
//                  medium.
// 091213c- aha42 - Now gets ServletContext in init method and implemented
//                  handling of default request (no params) to forward 
//                  /index.html.
//

package org.aha.webfg;

import java.io.BufferedReader;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aha.mf4j.FlickrCalls;
import org.aha.mf4j.FlickrException;
import org.aha.mf4j.FlickrSession;
import org.aha.mf4j.FlickrUrls;
import org.aha.mf4j.response.FlickrObject;
import org.aha.mf4j.response.FlickrResponseException;
import org.aha.servlet.RequestParseException;

/**
 * <p>
 *   Base class for 
 *   {@link WebfgPageCreator} implementation.
 * </p>
 * @author Arne Halvorsen (aha42)
 */
public abstract class AbstractWebfgPageCreator implements WebfgPageCreator 
{
  protected FlickrSession m_fs=null;
  
  protected FlickrCalls m_fc=null;
  
  protected ServletContext m_sc=null;
  
  protected String m_key=null;
  
  /**
   * <p>
   *   Constructor.
   * </p>
   */
  protected AbstractWebfgPageCreator(){}
  
  // Specified in WebfgPageCreator.
  public void init(FlickrSession fs, ServletContext sc) 
  {
    if (fs==null)
    {
      throw new NullPointerException("fs");
    }
    if (sc==null)
    {
      throw new NullPointerException("sc");
    }

    m_fs=fs;
    m_fc=new FlickrCalls(fs);
    m_sc=sc;
  }

  // Specified in WebfgPageCreator.  
  public void handleDefaultReq(HttpServletRequest req, HttpServletResponse resp)
    throws IOException 
  {
    InputStream is=null;
    try
    {
      resp.setContentType("text/html");
      PrintWriter pw=resp.getWriter();
      
      is=m_sc.getResourceAsStream("/index.html");
      InputStreamReader isr=new InputStreamReader(is, "UTF-8");
      BufferedReader br=new BufferedReader(isr);
      String line=br.readLine();
      while (line!=null)
      {
        pw.println(line);
        line=br.readLine();
      }
    }
    finally
    {
      if (is!=null) try { is.close(); } catch (IOException _){}
    }
  }

  // Specified in WebfgPageCreator.
  public void handleInfoReq(HttpServletRequest req, HttpServletResponse resp)
    throws IOException 
  {
    String nsid=req.getParameter("nsid");
    
    if (nsid!=null)
    {
      FlickrObject[] forest=m_fc.getCollectionTrees(null, nsid);
      WebfgUtil.showForest(forest, resp);
    }
    else
    {
      StringBuilder sb=htmlStart();
      sb.append("<p>No nsid, no info!</p>");
      htmlEnd(sb, resp);
    }
  }
  
  // Specified in WebfgPageCreator.
  public void handleUnknownReq(HttpServletRequest req, HttpServletResponse resp)
    throws IOException 
  {
    StringBuilder sb=htmlStart();
      
    sb.append("<h1>Info On Unknown Request</h1>");
    WebfgUtil.printParameters(sb, req);
     
    htmlEnd(sb, resp);  
  }
  
  // Specified in WebfgPageCreator.
  public void handleError(Throwable t, HttpServletResponse resp)
    throws IOException 
  {
    StringBuilder sb=htmlStart(false);
    
    sb.append("<h1>Sorry, there seem to be a technical problem...</h1>");
    
    String msg=t.getLocalizedMessage();
    msg=(msg==null) ? "" : msg.trim();
    
    if (t instanceof FlickrResponseException)
    {
      sb.append("<p>Flickr is reporting an error");
    }
    else if (t instanceof FlickrException)
    {
      sb.append("<p>It seems to be a problem communicating with Flickr");
    }
    else if (t instanceof RequestParseException)
    {
      sb.append("<p>It seems to be a problem with parsing the HTTP request");
    }
    else
    {
      sb.append("<p>Not classified error");  
    }
    if (msg.length()>0) sb.append(" : ").append(msg);
    sb.append(".</p>");
    
    sb.append(
      "<p><a class='markedLink' href='/'>Back to app's home page</a></p>");
    
    sb.append("<h2>Developer's info</h2>");
    sb.append("<pre>");
    
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    t.printStackTrace(pw);
    sb.append(caw);
    
    sb.append("</pre>");
    
    htmlEnd(sb, resp);
  }

  protected static void doDataAccessError(String error, 
    HttpServletResponse resp) throws IOException
  {
    StringBuilder sb=htmlStart();
    sb.append("<h1>Data Access Error</h1>").append(error);
    htmlEnd(sb, resp);
  }

  protected String createPieceHtml(FlickrObject piece, String nsid, String exid, 
    String size) throws IOException
  {
    // Gets exhibition title : sets title.
    //FlickrObject exInfoFo=m_fs.createRequest("flickr.photosets.getInfo")
    //  .setArg("photoset_id", exid).perform().getMandatoryChild("photoset");
    //FlickrObject titleFo=exInfoFo.getChild("title");
    //String exTitle=(titleFo==null) ? null : titleFo.getValue();
    //exTitle=(exTitle==null) ? "*" : exTitle;
  
    String id=piece.getMandatoryAttribute("id");
    
    Map<String, String> tags=TagUtil.getNameValueTags(m_fs, id);
    String localTitle=tags.get("webfg.title");
    String localSize=tags.get("webfg.size");
    
    size=(localSize==null) ? size : localSize;
  
    FlickrObject[] sizeFos=m_fc.getPhotoSizes(id);
  
    String title=(localTitle==null) ? piece.getAttribute("title") : localTitle;
  
    FlickrObject sizeFo=WebfgUtil.getSizeFo(sizeFos, size);
  
    int width=sizeFo.getMandatoryIntAtrribute("width");
    int height=sizeFo.getMandatoryIntAtrribute("height");
  
    String photoPageUrl=FlickrUrls.createPhotoWebUrlSpec(nsid, id);
  
    // TODO: Investigate why second seems to have a problem.
    String srcUrl=sizeFo.getAttribute("source");
    //String srcUrl=FlickrUrls.createPhotoUrlSpec(piece);
  
    String alt=(title==null) ? photoPageUrl : title;
  
    StringBuilder sb=new StringBuilder();
  
    //sb.append("<h1 class='pieceTitle'>").append(exTitle).append("</h1>");
  
    sb.append("<p class='piece'>");
  
    sb.append("<a href='").append(photoPageUrl).append("'><image src='")
      .append(srcUrl).append("' alt='").append(alt).append("' width='")
      .append(width).append("' height='").append(height).append("' /></a>");
  
   if (title!=null) sb.append("<br /><br />").append(title);
  
    sb.append("</p>");
  
    return sb.toString();
  }

  protected String createPlainPhotoHtml(FlickrObject photo, String nsid) 
    throws IOException
  {
    StringBuilder sb=new StringBuilder();
     
    String id=photo.getMandatoryAttribute("id");
  
    FlickrObject[] sizeFos=m_fc.getPhotoSizes(id);
  
    FlickrObject sizeFo=WebfgUtil.getSizeFo(sizeFos, "m");
  
    int width=sizeFo.getMandatoryIntAtrribute("width");
    int height=sizeFo.getMandatoryIntAtrribute("height");
  
    String photoPageUrl=FlickrUrls.createPhotoWebUrlSpec(nsid, id);
  
    // TODO: Investigate why second seems to have a problem.
    String srcUrl=sizeFo.getAttribute("source");
    //String srcUrl=FlickrUrls.createPhotoUrlSpec(piece);
  
    //sb.append("<p class='piece'>");
  
    sb.append("<a href='").append(photoPageUrl).append("'><image src='")
      .append(srcUrl).append("' alt='profile' width='").append(width)
      .append("' height='").append(height)
      .append("' align='left' border='0'/></a>");
  
    //sb.append("</p>");
  
    return sb.toString();
  }

  /**
   * <p>
   *   Gets URL specification of a piece (photo) page.
   * </p>
   * @param exid Id of Flickr set defining exhibition.
   * @param nsid User's id.
   * @param gid  Id of collection defining the gallery.
   * @param idx  Index in set that defines exhibition.
   * @param l    License text, may be {@code null} for 
   *             {@code "All Rights Reserved"}.
   * @return URL specification.
   */
  protected static String getPieceUrl(String exid, String nsid, String gid, 
    int idx, String l)
  {
    StringBuilder sb=new StringBuilder();
    sb.append("webfg").append("?where=piece").append("&exid=").append(exid)
      .append("&nsid=").append(nsid).append("&gid=").append(gid);
    if (idx!=-1) sb.append("&idx=").append(idx);
    if (l!=null)
    {
      try
      {
        sb.append("&l=").append(URLEncoder.encode(l, "UTF-8"));
      }
      catch (UnsupportedEncodingException uex)
      {
        // Not likely...
      }
    }
    return sb.toString();
  }
  
  /**
   * <p>
   *   Common HTML for all pages.
   * </p>
   * @return {@link StringBuilder} to compile HTML in.
   */
  protected static StringBuilder htmlStart(){ return htmlStart(true); }
  
  /**
   * <p>
   *   Common HTML for all pages.
   * </p>
   * @param style {@code true} if to attach css style sheet, {@code false} if 
   *              not to.
   * @return {@link StringBuilder} to compile HTML in.
   */
  protected static StringBuilder htmlStart(boolean style) 
  {
    StringBuilder sb=new StringBuilder();
    sb.append("<html>").append("<head>");
    
    if (style)
      sb.append("<link rel='stylesheet' type='text/css' href='def.css' />");
      
    return sb.append("</head>").append("<body>");
  }
  
  /**
   * <p>
   *   Prints common end HTML for all pages and writes generated HTML to client.
   * </p>
   * @param sb   {@link StringBuilder} to compile HTML in.
   * @param resp Response to write HTML to.
   * @throws IOException If fails.
   */
  protected static void htmlEnd(StringBuilder sb, HttpServletResponse resp) 
    throws IOException
  {
    sb.append("</body></html>");
    resp.setContentType("text/html");
    PrintWriter pw=resp.getWriter();
    pw.println(sb);
    pw.flush();
  }

}
